package com.ytt.core.service.service.user;

import com.github.wenhao.jpa.Specifications;
import com.ytt.core.model.common.PageDataDTO;
import com.ytt.core.model.common.SimpleDataDTO;
import com.ytt.core.model.user.UserDto;
import com.ytt.core.model.user.UserEditDTO;
import com.ytt.core.model.user.UserRegisterDTO;
import com.ytt.core.service.entity.role.Role;
import com.ytt.core.service.entity.user.User;
import com.ytt.core.service.exception.NoSuchDataException;
import com.ytt.core.service.mapper.user.UserMapper;
import com.ytt.core.service.repository.RoleRepository;
import com.ytt.core.service.repository.UserRepository;
import com.ytt.core.service.service.role.RoleService;
import com.ytt.core.service.utils.PageDataUtil;
import com.ytt.core.util.jpa.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * UserImpl
 *
 * @author chenwen
 * @date 2019/9/12 15:57
 */
@Slf4j
@Service("userService")
@Transactional(readOnly = true, rollbackFor = Exception.class)
public class UserImpl implements UserService {
    private static final String PASS_PLACE_HOLDER = "$pWd$(C%#*(78))!<>";
    private  final UserRepository userRepository;
    private  final UserMapper userMapper;
    private final RoleService roleService;
    private  final RoleRepository roleRepository;

    public UserImpl(UserRepository userRepository, UserMapper userMapper, RoleService roleService, RoleRepository roleRepository) {
        this.userRepository = userRepository;
        this.userMapper = userMapper;
        this.roleService = roleService;
        this.roleRepository = roleRepository;
    }

    @Override
    public String findByAccount(String account) {
        Long id = userRepository.findByAccount(account);
        if (id == null) {
           return  null;
        } else {
            return String.valueOf(id);
        }
    }

    @Override
    public String findByEmail(String mail) {
        Long id = userRepository.findByMail(mail);
        if (id == null) {
            return null;
        } else {
            return String.valueOf(id);
        }
    }

    @Override
    public UserDto findById(String id) {
        Optional<User> o = userRepository.findById(Long.parseLong(id));
        if(o.isPresent()){
            Set<String> authorities = new HashSet<>();
            //设置用户关联的权限
            o.get().getRoles().forEach(r -> authorities.addAll(roleService.getRoleAuthorities(r.getId())));

            UserDto userDto= userMapper.toDTO(o.get());
            userDto.setAuthorities(authorities);
            return  userDto;
        }else {
            throw new NoSuchDataException(id);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserDto create(UserEditDTO userEditDTO) {
        User user = userMapper.toEntity(userEditDTO);
        user.setPassword(new BCryptPasswordEncoder().encode(user.getPassword()));
        user = userRepository.saveAndFlush(user);

        //设置访问数据范围
//        user.setFilterPath(schoolDTO.getFilterPath()+"-"+user.getId());
//        user = userRepository.saveAndFlush(user);
        //todo 设置普通用户角色懒得做用户角色分配了
        Set<User> users;
        long[] ids={user.getId()};

        users = userRepository.findUsers(ids);
        // 再分配新的用户
        users.forEach(u -> {
            Optional<Role> role= roleRepository.findById(4L);
            if(role.isPresent()) {

                u.getRoles().add(role.get());
                userRepository.save(u);
            }
        });
        return userMapper.toDTO(user);
       
       
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserDto register(UserRegisterDTO userRegisterDTO) {
        User user = userMapper.toEntity(userRegisterDTO);
        user.setPassword(new BCryptPasswordEncoder().encode(user.getPassword()));
        user.setEnabled(true);
        user = userRepository.saveAndFlush(user);
        //设置用户访问范围
//        user.setFilterPath(schoolDTO.getFilterPath()+"-"+user.getId());
        user = userRepository.saveAndFlush(user);
        //todo 设置普通用户角色懒得做用户角色分配了
        Set<User> users;
        long[] ids={user.getId()};

        users = userRepository.findUsers(ids);
        // 再分配新的用户
        users.forEach(u -> {
            Optional<Role> role= roleRepository.findById(4L);
            if(role.isPresent()) {

                u.getRoles().add(role.get());
                userRepository.save(u);
            }
        });

        return userMapper.toDTO(user);
    }

    @Override
    public PageDataDTO<UserDto> findOnePage(int page, int size, String sort, String name,String filterPath) {
        PageRequest pr = PageHelper.generatePageRequest(page, size, sort);
        Specification<User> specification =Specifications.<User>and().
                like("filterPath",filterPath+"%").
                like(name != null && !"".equals(name) && !"null".equals(name), "name", "%" + name + "%")
                .build();
        Page<User> users = userRepository.findAll(specification, pr);
        List<UserDto> userDTOs = new ArrayList<>();
        List<User> userList = users.getContent();
        userList.forEach(user -> {
            UserDto userDTO = userMapper.toDTO(user);
            userDTO.setPassword(PASS_PLACE_HOLDER);
            userDTOs.add(userDTO);
        });
        return PageDataUtil.toPageData(users, userDTOs);
    }

    @Override
    public SimpleDataDTO<Boolean> checkAccountAvailability(String userId, String account) {
        String foundUserId = this.findByAccount(account);
        if (foundUserId == null) {
            return new SimpleDataDTO<>(true);
        } else {
            boolean rtn = userId != null && userId.equalsIgnoreCase(foundUserId);
            return new SimpleDataDTO<>(rtn);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserDto update(String id, UserEditDTO userEditDTO) {
        Optional<User> o = userRepository.findById(Long.valueOf(id));
        User user;
        if(o.isPresent()){
            user=o.get();
            String oldPwd = o.get().getPassword();

            userMapper.updateEntity(userEditDTO, user);
            if(!oldPwd.equals(userEditDTO.getPassword())){
                user.setPassword(new BCryptPasswordEncoder().encode(userEditDTO.getPassword()));
            }else {
                user.setPassword(oldPwd);
            }
            userRepository.saveAndFlush(user);
           return userMapper.toDTO(user);
        }else {
            throw  new NoSuchDataException(id);
        }
    }

    @Override
    public SimpleDataDTO<Boolean> checkEmailAvailability(String userId, String email) {
        String foundUserId = this.findByEmail(email);
        if (foundUserId == null) {
            return new SimpleDataDTO<>(true);
        } else {
            boolean rtn = userId != null && userId.equalsIgnoreCase(foundUserId);
            return new SimpleDataDTO<>(rtn);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(String userId) {
        Optional<User> userOptional = userRepository.findById(Long.valueOf(userId));
        if(userOptional.isPresent()){
            //解锁用户角色
            userOptional.get().getRoles().forEach(role -> {
                role.getUsers().remove(userOptional.get());
            });
            userRepository.delete(userOptional.get());
        }else{
            throw new NoSuchDataException(userId);
        }
    }


}
